home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
CollView.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-11
|
11KB
|
550 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "CollView.h"
#include "Class.h"
#include "String.h"
#include "SeqColl.h"
#include "VObject.h"
#include "CmdNo.h"
#include "Error.h"
#include "Math.h"
#include "WindowSystem.h"
extern bool testopen;
//---- CollectionView ----------------------------------------------------------
NewMetaImpl(CollectionView,View, (TP(coll), T(selection), T(gap), T(minExtent),
T(rows), T(cols), TP(defaultItem)));
CollectionView::CollectionView(EvtHandler *eh, SeqCollection *m, CollViewOptions o,
int r, int c) : View(eh, gRect0)
{
SetFlag(o);
defaultItem= new VObject();
rows= r;
cols= c;
SetCollection(m);
}
CollectionView::~CollectionView()
{
if (coll) {
coll->RemoveObserver(this);
coll->FreeAll();
SafeDelete(coll);
}
SafeDelete(xPos);
SafeDelete(yPos);
SafeDelete(defaultItem);
}
//---- init methods
void CollectionView::SetSelection(Rectangle newsel, bool sendcontrol)
{
if (selection != newsel) {
if (IsOpen()) {
InvalidateRect(ItemRect(selection));
InvalidateRect(ItemRect(newsel));
}
selection= newsel;
}
if (sendcontrol)
DoSelect(selection, WindowSystem::Clicks);
}
void CollectionView::SetColsRows(Point cr)
{
cols= cr.x;
rows= cr.y;
Modified();
}
void CollectionView::DoSelect(Rectangle r, int clicks)
{
if (r.IsNotEmpty()) {
int partcode= clicks >= 2 ? cPartCollDoubleSelect : cPartCollSelect;
Control(GetId(), partcode, (void*) r.origin.y);
}
}
void CollectionView::ClearSelection(bool)
{
SetSelection(gRect0);
}
void CollectionView::SetCollection(SeqCollection *m, bool freeold)
{
if (coll) {
coll->RemoveObserver(this);
/*
{
coll->ForEach(VObject,Open)(FALSE);
}
*/
{
coll->ForEach(VObject,ClearContainer)(this);
}
if (freeold) {
coll->FreeAll();
delete coll;
}
}
coll= m;
if (coll) {
coll->AssertClass(VObject);
{
coll->ForEach(VObject,SetContainer)(this);
}
if (IsOpen()) {
coll->ForEach(VObject,Open)(TRUE);
}
coll->AddObserver(this);
}
selection= gRect0;
Modified();
//if (IsOpen())
// Scroll(cPartScrollAbs, gPoint0, FALSE);
}
void CollectionView::SetDefaultItem(class VObject *d)
{
if (defaultItem)
delete defaultItem;
defaultItem= d;
}
void CollectionView::SetMinExtent(Point e)
{
if (minExtent != e) {
minExtent= e;
Modified();
}
}
Metric CollectionView::GetMinSize()
{
Update();
return GetExtent();
}
void CollectionView::Open(bool m)
{
View::Open(m);
if (testopen) {
if (m) {
if (coll) {
coll->ForEach(VObject,Open)(TRUE);
}
} else {
if (!IsOpen() && coll) {
coll->ForEach(VObject,Open)(FALSE);
}
}
}
}
//---- layout
void CollectionView::ConstrainScroll(Point *p)
{
if (xPos) {
bool outside;
Point pp= PointToItem(*p, &outside);
if (! outside)
p->y= ItemRect(0, pp.y).origin.y;
}
}
void CollectionView::SetOrigin(Point at)
{
View::SetOrigin(at);
if (coll && coll->Size() > 0) {
register int x, y;
at+= gap;
for (x= 0; x < cols; x++)
for (y= 0; y < rows; y++)
GetItem(x, y)->SetOrigin(Point(xPos[x]+at.x, yPos[y]+at.y));
}
}
void CollectionView::Update()
{
register VObject *gop;
register int x, y, ww, hh, w, h;
int xpos= 0, ypos= 0, sz;
Point g;
if (!TestFlag(eCVModified))
return;
ResetFlag(eCVModified);
if (coll == 0 || coll->Size() <= 0) {
ForceRedraw();
return;
}
if (testopen) {
{
coll->ForEach(VObject,SetContainer)(this);
}
if (IsOpen()) {
coll->ForEach(VObject,Open)(TRUE);
}
}
sz= coll->Size();
if (rows <= 0)
SetFlag(eCVExpandRows);
if (cols <= 0)
SetFlag(eCVExpandCols);
if (TestFlag(eCVExpandRows) && TestFlag(eCVExpandCols)) {
cols= Math::Sqrt(sz);
rows= (sz+cols-1) / cols;
} else if (TestFlag(eCVExpandRows))
rows= (sz+cols-1) / cols;
else if (TestFlag(eCVExpandCols))
cols= (sz+rows-1) / rows;
yPos= (int*) Realloc(yPos, (rows+1) * sizeof(int));
xPos= (int*) Realloc(xPos, (cols+1) * sizeof(int));
xpos= ypos= 0;
g= 2*gap;
if (TestFlag(eCVGrid))
g+= gPoint1;
for (x= 0; x < cols; x++) {
xPos[x]= xpos;
ww= minExtent.x;
for (y= 0; y < rows; y++) {
gop= GetItem(x, y);
gop->SetContainer(this);
if (!testopen) {
if (IsOpen())
gop->Open();
}
gop->CalcExtent();
w= gop->Width();
ww= Math::Max(ww, w);
}
xpos+= ww+g.x;
}
xPos[x]= xpos;
for (y= 0; y < rows; y++) {
yPos[y]= ypos;
hh= minExtent.y;
for (x= 0; x < cols; x++) {
h= GetItem(x, y)->Height();
hh= Math::Max(hh, h);
}
ypos+= hh+g.y;
}
yPos[y]= ypos;
for (x= 0; x < cols; x++)
for (y= 0; y < rows; y++)
GetItem(x, y)->SetContentRect(ItemRect(x, y).Inset(gap), FALSE);
if (TestFlag(eCVGrid)) {
xpos--;
ypos--;
}
ForceRedraw();
SetExtent(Point(xpos, ypos));
ForceRedraw();
}
//---- update
void CollectionView::DoObserve(int, int part, void *, Object *op)
{
if (part == cPartSenderDied)
coll= 0;
else if (op == coll)
Modified();
}
void CollectionView::Modified()
{
SetFlag(eCVModified);
if (IsOpen())
Update();
}
//---- mapping
Point CollectionView::PointToItem(Point p, bool *outside)
{
register int x, y;
register bool out= FALSE;
if (coll == 0 || coll->Size() <= 0) {
if (outside)
*outside= TRUE;
return gPoint0;
}
Update();
p-= GetOrigin();
if (p.x < xPos[0]) {
out= TRUE;
x= 0;
} else if (p.x >= xPos[cols]) {
out= TRUE;
x= cols-1;
} else {
for (x= 0; x < cols; x++)
if (p.x >= xPos[x] && p.x < xPos[x+1])
break;
}
if (p.y < yPos[0]) {
out= TRUE;
y= 0;
} else if (p.y >= yPos[rows]) {
out= TRUE;
y= rows-1;
} else {
for (y= 0; y < rows; y++)
if (p.y >= yPos[y] && p.y < yPos[y+1])
break;
}
if (outside)
*outside= out;
return Point(x, y);
}
Rectangle CollectionView::ItemRect(Rectangle r)
{
Rectangle rr;
if (r.IsEmpty())
return gRect0;
Update();
rr.origin.x= xPos[r.origin.x];
rr.origin.y= yPos[r.origin.y];
rr.extent.x= xPos[r.origin.x+r.extent.x] - rr.origin.x;
rr.extent.y= yPos[r.origin.y+r.extent.y] - rr.origin.y;
if (TestFlag(eCVGrid))
rr.extent-= gPoint1;
return rr+GetOrigin();
}
Point CollectionView::ItemPos(VObject *g)
{
VObject *gop;
Iter next(coll);
Update();
for (int i= 0; gop= (VObject*) next(); i++)
if (gop == g)
break;
if (i >= coll->Size())
return gPoint_1;
return Point(i % cols, i / cols);
}
Rectangle CollectionView::ItemRect(int x, int y)
{
Update();
x= Math::Range(0, cols-1, x);
y= Math::Range(0, rows-1, y);
Rectangle r(xPos[x], yPos[y], xPos[x+1]-xPos[x], yPos[y+1]-yPos[y]);
if (TestFlag(eCVGrid))
r.extent-= gPoint1;
r.origin+= GetOrigin();
return r;
}
VObject *CollectionView::GetItem(int x, int y)
{
VObject *vop= 0;
int ix= y*cols+x;
if (ix >= 0 && ix < coll->Size())
vop= (VObject*)coll->At(ix);
return vop ? vop : defaultItem;
}
//---- event handlung
Command *CollectionView::DoLeftButtonDownCommand(Point lp, Token t, int clicks)
{
if (coll && coll->Size() > 0) {
ClearSelection();
return new CellSelector(this, TestFlag(eCVDontStuckToBorder));
}
return View::DoLeftButtonDownCommand(lp, t, clicks);
}
Command *CollectionView::DoKeyCommand(int ch, Token)
{
register VObject *gop= 0;
register int i;
int start= 0;
Rectangle r= GetViewedRect();
if (r.IsNotEmpty()) {
start= r.origin.y+r.extent.y;
if (start <= GetExtent().y)
start= PointToItem(Point(0,start)).y;
}
for (i= 0; i < rows; i++) {
gop= GetItem(0, (start+i) % rows);
if (gop && (sortmap[gop->AsString()[0]] == sortmap[ch]))
break;
}
if (gop)
RevealAlign(ItemRect(Rectangle(ItemPos(gop), gPoint1)));
return gNoChanges;
}
//---- drawing
void CollectionView::Draw(Rectangle r)
{
register int x, y;
register VObject *gop;
Point p1, p2;
if (coll == 0 || coll->Size() <= 0)
return;
p1= PointToItem(r.NW());
p2= PointToItem(r.SE()+gPoint1);
int i= 0;
for (x= p1.x; x <= p2.x; x++) {
for (y= p1.y; y <= p2.y; y++) {
i++;
gop= GetItem(x, y);
gop->DrawAll(gop->contentRect,
selection.ContainsPoint(Point(x, y)) && gop->Enabled());
}
}
if (TestFlag(eCVGrid)) {
GrSetPenNormal();
DrawGrid(p1, p2);
}
}
void CollectionView::DrawGrid(Point p1, Point p2)
{
register int x, y;
int xx= 0, yy= 0;
Point o= GetOrigin();
if (p2.x >= cols-1)
xx= 1;
if (p2.y >= rows-1)
yy= 1;
for (x= p1.x; x <= p2.x-xx; x++)
GrLine(Point(xPos[x+1]-1, yPos[p1.y])+o, Point(xPos[x+1]-1, yPos[p2.y+1]-1)+o);
for (y= p1.y; y <= p2.y-yy; y++)
GrLine(Point(xPos[p1.x], yPos[y+1]-1)+o, Point(xPos[p2.x+1]-1, yPos[y+1]-1)+o);
}
//---- input/output
OStream& CollectionView::PrintOn(OStream &s)
{
Object::PrintOn(s);
return s << gap SP << minExtent SP << rows SP << cols SP << defaultItem SP << coll SP;
}
bool CollectionView::PrintOnWhenObserving(Object *from)
{
return from != coll;
}
IStream& CollectionView::ReadFrom(IStream &s)
{
SeqCollection *m;
VObject *di= 0;
Object::ReadFrom(s);
s >> gap >> minExtent >> rows >> cols >> di >> m;
SetCollection(m);
SetDefaultItem(di);
return s;
}
void CollectionView::CollectParts(Collection* col)
{
View::CollectParts(col);
if (coll && coll->Size() < 12) // hack
col->Add(coll);
}
VObject *CollectionView::Detect(BoolFun find, void *arg)
{
if (coll) {
Iter next(coll);
register VObject *v1, *v2;
while (v1= (VObject*) next())
if (v2= v1->Detect(find, arg))
return v2;
}
return 0;
}
//---- CellSelector ------------------------------------------------------------
CellSelector::CellSelector(CollectionView* v, bool dontstucktoborder)
{
SetFlag(eCmdNoReplFeedback);
lvp= v;
last= 0;
dontstuck= dontstucktoborder;
}
void CellSelector::TrackFeedback(Point, Point pp, bool on)
{
if (on) {
if (itemptr == last) {
if (last)
last->DoTrackMouse((TrackPhase)eTrackMove, pp);
} else {
if (last)
last->DoTrackMouse((TrackPhase)eTrackRelease, pp);
if (itemptr)
itemptr->DoTrackMouse((TrackPhase)eTrackPress, pp);
}
last= itemptr;
}
}
Command *CellSelector::TrackMouse(TrackPhase atp, Point, Point, Point np)
{
bool outside= FALSE;
item= lvp->PointToItem(np, &outside);
if (outside && dontstuck)
itemptr= 0;
else
itemptr= lvp->GetItem(item.x, item.y);
switch (atp) {
case eTrackRelease:
if (last)
last->DoTrackMouse((TrackPhase)eTrackRelease, np);
if (itemptr && itemptr->Enabled())
lvp->SetSelection(Rectangle(item, gPoint1), TRUE);
else
lvp->SetSelection(gRect0, TRUE);
case eTrackExit:
return gNoChanges;
default:
break;
}
return this;
}